﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace Wise.Util.Queryable
{
    class DbHelper
    {
        static Regex _IsAllUpcaseOrLowercase = new Regex("^([A-Z]+|[a-z]+)$", RegexOptions.Compiled);

        static Regex _IsAllUpcase =new Regex("[A-Z]", RegexOptions.Compiled);



        internal static void initRangeValue(_Parameter para)
        {
            if (para.Field.IndexOf("Date", StringComparison.CurrentCultureIgnoreCase) > -1)
            {
                if (para.Field[0] == '>' || para.Field[0] == '》')
                {
                    DateTime dt = para.GetValue<DateTime>();
                    para.Value = dt.Date;
                }
                else if (para.Field[0] == '<' || para.Field[0] == '《')
                {
                    DateTime dt = para.GetValue<DateTime>();
                    para.Value = dt.Date.AddDays(1);
                }
            }
        }

        static PropertyInfo _GetProperty(List<PropertyInfo> props, string fieldName, List<string> builder, bool needChangeLast = true)
        {
            PropertyInfo p = null;
            if (p == null)
            {
                p = props.Where(x => x.Name == fieldName).FirstOrDefault();
            }
            if (p == null)
            {
                #region 去掉前缀搜索
                p = props.Where(x =>
                     string.Equals(x.Name, fieldName, StringComparison.CurrentCultureIgnoreCase))
                    .FirstOrDefault();
                if (fieldName.Contains("_"))
                {
                    string newFieldName = fieldName.Replace("_", "");
                    p = props.Where(x =>
                         string.Equals(x.Name, newFieldName, StringComparison.CurrentCultureIgnoreCase))
                        .FirstOrDefault();
                    if (p != null && needChangeLast)
                    {
                        string some = builder.Last();
                        builder.RemoveAt(builder.Count - 1);
                        builder.Add(some.Replace(fieldName, newFieldName));
                    }
                }
                else if (!_IsAllUpcaseOrLowercase.IsMatch(fieldName))
                {
                    #region  //全部都是大写或小写
                    var mcs = _IsAllUpcase.Matches(fieldName);
                    List<string> b = new List<string>();
                    int last = 0;
                    foreach (Match match in mcs)
                    {
                        if (match.Index == 0)
                            continue;
                        b.Add(fieldName.Substring(last, match.Index - last));
                        last = match.Index;
                    }
                    if (b.Count > 0)
                    {
                        b.Add(fieldName.Substring(last));
                        string newFieldName = string.Join("_", b);
                        p = props.Where(x =>
                        string.Equals(x.Name, newFieldName, StringComparison.CurrentCultureIgnoreCase))
                         .FirstOrDefault();
                        if (p != null && needChangeLast)
                        {
                            string some = builder.Last();
                            builder.RemoveAt(builder.Count - 1);
                            builder.Add(some.Replace(fieldName, newFieldName));
                        }
                    }
                    #endregion
                }
                //if (p == null)
                //{
                //throw new Exception(string.Format("未能在类型[{0}]上找到字段[{1}]", typeof(TModel), fieldName));
                //}
                #endregion
            }
            return p;
        }

        public static bool ContainsField(string dataViewName, string field)
        {
            return GetQueryFields(dataViewName)
                .Any(x => string.Equals(x.Item1, field, StringComparison.CurrentCultureIgnoreCase));
        }

        /// <summary>
        /// 生成查询条件
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <param name="_Request"></param>
        /// <param name="source"></param>
        /// <returns></returns>
        public static Expression<Func<TModel, bool>> CreatePredict<TModel>(MyQuery _Request, IQueryable<TModel> source)
        {
            List<string> builder = new List<string>();
            List<object> values = new List<object>();
            var props = ObjectHelper.GetObjectPropertyMap(typeof(TModel), true);
            List<LambdaExpression> exists = new List<LambdaExpression>();
            foreach (_Parameter para in _Request)
            {
                if (para.IsNull || string.IsNullOrEmpty(para.Field))
                {
                    continue;
                }
                string fieldName = null;
                PropertyInfo p = null;
                bool needAddValue = true;
                //values.Count 表示序号，例如 Id = @1 ,DynamicQuery会将其自动传入正确参数
                if (para.Field == "_Items")
                {
                    if (ContainsField(_Request._DataViewName, "Id"))
                    {
                        builder.Add(string.Format(" {0} IN (@{1}) ", "Id", values.Count));
                    }
                    continue;
                }
                else if (para.Field == "current")
                {
                    #region current
                    fieldName = para.Field;
                    p = props.Where(x => x.Name == "Id").FirstOrDefault();
                    if (p == null)
                    {
                        continue;
                    }
                    else
                    {
                        builder.Add(string.Format(" {0} != @{1} ", "Id", values.Count));
                    }
                    #endregion
                }
                else if (para.Field == "dependence")
                {
                    #region  todo:[不重要]暂不支持外键约束或子级查询
                    //bool hasParent = false;
                    //for (int i = 0; i < columns.Count; i++)
                    //{
                    //    AmsKeyValue<string, Type> cur = columns[i];
                    //    if (cur.Key == "parentid")
                    //    {
                    //        hasParent = true;
                    //        break;
                    //    }
                    //}
                    //if(hasParent)
                    //{
                    //    builder.Add(string.Format("[{0}] != '{1}' ", para.Field, fieldValue));
                    //}
                    #endregion
                }
                else if (para.Field == "ParentId")
                {
                    builder.Add(string.Format(" ( {0}.Value.Equals( @{1}) OR Id.Equals(@{1}) ) ", para.Field, values.Count));
                }
                else if (MyQuery._IsBadParameter.IsMatch(para.Field))
                {
                    continue;
                }
                else
                {
                    string preview = MyQuery._Preview.Match(para.Field).Value;
                    fieldName = para.Field.Remove(0, preview.Length);
                    p = _GetProperty(props, fieldName, builder, false);
                    if (p == null)
                    {
                        //SimpleAppHelper.InstanceFromCache.Waring("类型{typeof(TModel).FullName}不包含{fieldName}的公共定义!");
                        builder.Add(" 1=2 ");
                        continue;
                    }
                    #region 处理常规字段
                    switch (preview)
                    {
                        #region 大小比较 >< 》《
                        case "<=":
                        case "《=":
                            {
                                if (p.PropertyType.IsNullable())
                                {
                                    builder.Add(string.Format("{0}.Value <= @{1} ", fieldName, values.Count));
                                }
                                else
                                {
                                    builder.Add(string.Format("{0} <= @{1} ", fieldName, values.Count));
                                }
                                DbHelper.initRangeValue(para);
                            }
                            break;
                        case "<":
                        case "《":
                            {
                                if (p.PropertyType.IsNullable())
                                {
                                    builder.Add(string.Format("{0}.Value < @{1} ", fieldName, values.Count));
                                }
                                else
                                {
                                    builder.Add(string.Format("{0} < @{1} ", fieldName, values.Count));
                                }
                                DbHelper.initRangeValue(para);
                            }
                            break;
                        case ">=":
                        case "》=":
                            {
                                if (p.PropertyType.IsNullable())
                                {
                                    builder.Add(string.Format("{0}.Value >= @{1} ", fieldName, values.Count));
                                }
                                else
                                {
                                    builder.Add(string.Format("{0} >= @{1} ", fieldName, values.Count));
                                }
                                DbHelper.initRangeValue(para);
                            }
                            break;
                        case ">":
                        case "》":
                            {
                                if (p.PropertyType.IsNullable())
                                {
                                    builder.Add(string.Format("{0}.Value > @{1} ", fieldName, values.Count));
                                }
                                else
                                {
                                    builder.Add(string.Format("{0} > @{1} ", fieldName, values.Count));
                                }
                                DbHelper.initRangeValue(para);
                            }
                            break;

                        #endregion

                        #region 序列 ! @
                        case "!":
                            {
                                needAddValue = false;
                                p = _GetProperty(props, fieldName, builder, false);
                                if (p == null)
                                {
                                    builder.Add(" 1=2 ");
                                }
                                else
                                {
                                    builder.Add(string.Format(" !@{1}.Contains({0}) ", fieldName, values.Count));
                                    Object a = null;
                                    if (p.PropertyType == typeof(Guid))
                                    {
                                        a = para.StringValue.Trim(new char[] { '[', ']' }).Split(',')
                                             .Select(x => new Guid(x.Trim('\"')))
                                             .ToList();
                                    }
                                    else if (p.PropertyType == typeof(Guid?))
                                    {
                                        a = para.StringValue.Trim(new char[] { '[', ']' }).Split(',')
                                            .Select(x => (Guid?)new Guid(x.Trim('\"')))
                                            .ToList();
                                    }
                                    values.Add(a);
                                }
                            }
                            break;
                        case "@":
                            {
                                needAddValue = false;
                                p = _GetProperty(props, fieldName, builder, false);
                                if (p == null)
                                {
                                    builder.Add(" 1=2 ");
                                }
                                else
                                {
                                    builder.Add(string.Format(" @{1}.Contains( {0} ) ", fieldName, values.Count));
                                    Object a = null;
                                    if (p.PropertyType == typeof(Guid))
                                    {
                                        a = para.StringValue.Trim(new char[] { '[', ']' }).Split(',')
                                             .Select(x => new Guid(x.Trim('\"')))
                                             .ToList();
                                    }
                                    else if (p.PropertyType == typeof(Guid?))
                                    {
                                        a = para.StringValue.Trim(new char[] { '[', ']' }).Split(',')
                                            .Select(x => (Guid?)new Guid(x.Trim('\"')))
                                            .ToList();
                                    }
                                    values.Add(a);
                                }
                            }
                            break;
                        #endregion

                        #region 模糊搜索与分词搜索 -
                        case "-":
                            {
                                string value = para.StringValue.ToUpper().Trim();
                                if (value.Contains(" "))
                                {
                                    #region 分词模糊查询 //todo:未来实现自动分词功能
                                    List<string> qb = new List<string>();
                                    var array = value.Split(' ').Where(x => !string.IsNullOrEmpty(x)).ToArray();
                                    foreach (string parter in array)
                                    {
                                        if (source.Provider.GetType().Name == "DbQueryProvider")
                                        {
                                            if (fieldName == "Name" && props.Any(y => y.Name == "Code"))
                                            {
                                                qb.Add(string.Format(" Name.Contains( @{0} ) Or Code.Contains( @{0}) ", values.Count));
                                            }
                                            else
                                            {
                                                qb.Add(string.Format(" {0}.ToString().Contains( @{1} ) ", fieldName, values.Count));
                                            }
                                        }
                                        else
                                        {
                                            if (fieldName == "Name" && props.Any(y => y.Name == "Code"))
                                            {
                                                qb.Add(string.Format(" Name.ToUpper().Contains( @{0} ) Or Code.ToUpper().Contains( @{0}) ", values.Count));
                                            }
                                            else
                                            {
                                                qb.Add(string.Format(" {0}.ToString().ToUpper().Contains( @{1} ) ", fieldName, values.Count));
                                            }
                                        }
                                        values.Add(parter);
                                    }
                                    builder.Add(string.Concat("(", string.Join(" OR ", qb), ")"));
                                    #endregion
                                    continue;
                                }
                                else
                                {
                                    #region 常规模糊查询
                                    if (source.Provider.GetType().Name == "DbQueryProvider")
                                    {
                                        if (fieldName == "Name" && props.Any(y => y.Name == "Code"))
                                        {
                                            builder.Add(string.Format("( Name.Contains( @{0} ) Or Code.Contains( @{0}) )", values.Count));
                                        }
                                        else
                                        {
                                            builder.Add(string.Format("{0}.ToString().Contains( @{1} )", fieldName, values.Count));
                                        }
                                    }
                                    else
                                    {
                                        if (fieldName == "Name" && props.Any(y => y.Name == "Code"))
                                        {
                                            builder.Add(string.Format("( Name.ToUpper().Contains( @{0} ) Or Code.ToUpper().Contains( @{0}) )", values.Count));
                                        }
                                        else
                                        {
                                            builder.Add(string.Format("{0}.ToString().ToUpper().Contains( @{1} )", fieldName, values.Count));
                                        }
                                        para.Value = value;
                                    }
                                    #endregion
                                }
                            }
                            break;
                        #endregion

                        #region 常规匹配 
                        default:
                            {
                                if (p.PropertyType.IsNullable())
                                {
                                    builder.Add(string.Format("{0}.Value.Equals( @{1} ) ", p.Name, values.Count));
                                }
                                else
                                {
                                    builder.Add(string.Format("{0}.Equals( @{1} ) ", p.Name, values.Count));
                                }
                            }
                            break;
                            #endregion

                    }
                    #endregion
                }
                if (needAddValue)
                {
                    if (p == null)
                    {
                        string preview = MyQuery._Preview.Match(para.Field).Value;
                        fieldName = para.Field.Remove(0, preview.Length);
                        p = _GetProperty(props, fieldName, builder, false);
                    }
                    if (p == null)
                    {
                        //SimpleAppHelper.InstanceFromCache.Waring("类型{typeof(TModel).FullName}不包含{fieldName}的公共定义!");
                        builder.RemoveAt(builder.Count - 1);
                        builder.Add(" 1=2 ");
                        continue;
                    }
                    values.Add(ObjectHelper.ChangeType(para.Value, p.PropertyType.UnpackNullable()));
                }
            }

            if (values.Count > 0 || builder.Count > 0)
            {
                #region 构造表达式树
                string lambdaExpression = string.Join(_Request.IsAndRelation ? " And " : " Or ", builder.ToArray());
                Expression<Func<TModel, bool>> exp = null;
                try
                {
                    exp = System.Linq.Dynamic.DynamicExpression
                        .ParseLambda<TModel, bool>(lambdaExpression, values.ToArray());
                }
                catch (Exception exception)
                {
                    throw new Exception(lambdaExpression, exception);
                }
                foreach (MyQuery q in _Request.QueryList)
                {
                    if (_Request.IsAndRelation)
                    {
                        exp = LambdaHelper.AndAlso<TModel>(exp, CreatePredict(q, source));
                    }
                    else
                    {
                        exp = LambdaHelper.OrElse<TModel>(exp, CreatePredict(q, source));
                    }
                }
                #endregion
                return exp;
            }
            return (t) => true;
        }

        /// <summary>
        /// 生成查询条件
        /// </summary>
        /// <param name="myQuery"></param>
        /// <returns></returns>
        internal static string CreatePredict(MyQuery myQuery)
        {
            throw new NotImplementedException();

        }

        /// <summary>
        /// 生成查询语句
        /// </summary>
        /// <param name="myQuery"></param>
        /// <param name="where"></param>
        /// <param name="top"></param>
        /// <returns></returns>
        internal static string MakeQueryString(MyQuery myQuery, string where, int top)
        {
            throw new NotImplementedException();
        }


        public static bool ContainsField_IsEnabled(string dataViewName)
        {
            return ContainsField(dataViewName, "IsEnabled");
        }
        public static bool ContainsField_Order_Weight(string dataViewName)
        {
            return ContainsField(dataViewName, "Order_Weight");
        }
        public static bool ContainsField_IsDelete(string dataViewName)
        {
            return ContainsField(dataViewName, "IsDelete");
        }
        public static bool ContainsField_Description(string dataViewName)
        {
            return ContainsField(dataViewName, "Description");
        }
        public static bool ContainsField_ParentId(string dataViewName)
        {
            return ContainsField(dataViewName, "ParentId");
        }
        public static bool ContainsField_Code(string dataViewName)
        {
            return ContainsField(dataViewName, "Code");
        }
        public static bool ContainsField_Name(string dataViewName)
        {
            return ContainsField(dataViewName, "Name");
        }
        public static bool ContainsField_CreatedOnDate(string dataViewName)
        {
            return ContainsField(dataViewName, "CreatedOnDate");
        }
        public static bool ContainsField_CreatedByUserId(string dataViewName)
        {
            return ContainsField(dataViewName, "CreatedByUserId");
        }

        /// <summary>
        /// 获取当前视图或表的所有字段信息
        /// </summary>
        /// <param name="_DataViewName"></param>
        /// <returns></returns>
        internal static List<Tuple<string, Type>> GetQueryFields(string _DataViewName)
        {
            return CacheHelper.Get<List<Tuple<string, Type>>, String>(
                String.Format("GetQueryFields.{0}", _DataViewName)
                , _doGetQueryFields
                , _DataViewName);
        }

        /// <summary>
        /// 查询当前视图或表的所有字段信息
        /// </summary>
        /// <param name="_DataViewName"></param>
        /// <returns></returns>
        static List<Tuple<string, Type>>  _doGetQueryFields(string _DataViewName)
        {
            throw new NotImplementedException();
            //List<Tuple<string, Type>> cc = new List<Tuple<string, Type>>();
            //IDataReader reader = null;
            //using (var con = DbHelper.GetDbConnection())
            //{
            //    con.Open();
            //    var cmd = con.CreateCommand();
            //    cmd.CommandText = string.Format("select * from {0} v where 1=2", dataViewName);
            //    reader = cmd.ExecuteReader();
            //    for (int i = 0; i < reader.FieldCount; i++)
            //    {
            //        string f = reader.GetName(i);
            //        Type ft = reader.GetFieldType(i);
            //        cc.Add(new Tupe<string, Type>(f, ft));
            //    }
            //}
            //return cc;
        }
    }
}
